package eiisan.config.security.settings;

import eiisan.config.security.error.AccessDenied;
import eiisan.config.security.error.AuthDenied;
import eiisan.config.security.filter.JwtAuthorizationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;

import java.util.ArrayList;
import java.util.List;

/*参考: http://www.blogjava.net/youxia/archive/2008/12/07/244883.html
理解security执行过程*/

/**
 * @Description: 用户认证配置
 * @Author gragonfly
 * @Date 2019/7/6
 **/
@Configuration
@EnableWebSecurity
//@EnableGlobalMethodSecurity(prePostEnabled = true) //启用方法上的注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 访问控制参数配置
     */
    @Autowired
    private SecurityProperties properties;
    /**
     * 无验证访问控制
     */
    @Autowired
    private AuthDenied authentication;

    /**
     * 无权限访问控制
     */
    @Autowired
    private AccessDenied accessDenied;
    /**
     * 验证信息获取服务
     */
    @Autowired
    @Qualifier("eiisanDTS")
    private UserDetailsService userDetailsService;
    /**
     * 自定义基于JWT的安全过滤器
     */
    @Autowired
    JwtAuthorizationTokenFilter authenticationTokenFilter;

    /**
     * 验证信息获取服务配置
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    // 搭配上面EnableGlobalMethodSecurity(prePostEnabled = true) 使用，去掉默认前缀
//    @Bean
//    GrantedAuthorityDefaults grantedAuthorityDefaults() {
//        // Remove the ROLE_ prefix
//        return new GrantedAuthorityDefaults("");
//    }

    /**
     * 密码加密器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 验证管理器
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 主配置
     */
    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        List<String> permitAllPathList = properties.getAuth().getPermitAllPath();
        httpSecurity
                // 禁用 CSRF
                .csrf().disable()
                //.httpBasic().and()  //这里不开启httpBasic，因为不需要 注册客户端。只要有用户密码都可以访问

                // 授权异常 无权限时导向noAuthPoint
                .exceptionHandling().authenticationEntryPoint(authentication).and().exceptionHandling().accessDeniedHandler(accessDenied).and()

                // 不创建会话
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

                // 过滤请求
                .authorizeRequests()
                .antMatchers(
                        HttpMethod.GET,
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                ).anonymous()

                // 配置文件中的 不控制的地址 permitAll
                .antMatchers(permitAllPathList.toArray(new String[0])).permitAll()

                //其他权限自定，不在这里配置
                //.antMatchers("/admin/**").hasRole("ADMIN")
                //.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")

                // 所有请求都需要认证
                .anyRequest().authenticated().and()

                // 防止iframe 造成跨域
                .headers().frameOptions().disable().and()

                //.formLogin() //开启登录

                // 在密码验证过滤器前执行jwtToken过滤器
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class).headers().cacheControl()
        ;

    }

    /**
     * 设置登出处理器
     */
    @Bean
    public SecurityContextLogoutHandler securityContextLogoutHandler() {
        return new SecurityContextLogoutHandler();
    }
}